<?php

namespace App\Models\Traits;

use App\Jobs\MakeSeckillOrderJob;
use App\Jobs\CloseSeckillOrderJob;
use App\Jobs\CloseOrderJob;
use App\Jobs\MakeSeckillOrderAddressJob;
use Carbon\Carbon;
use App\Models\SeckillProduct;
use App\Models\ProductSku;
use App\Models\Order;
use App\Models\User;
use Brick\Math\RoundingMode;
use App\Jobs\CloseUnpaidStormJob;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Collection;
use App\Services\MakeProductOrder\MakeProductOrder;

trait HasUserOrderUnpaidCache
{
	public static function sUnpaidOrderCacheKey($uid): string
	{
		return "user_{$uid}_unpaid_orders";
	}


	public static function sUnpaidOrderListCacheKey($uid,$uniqueId): string
	{
		return "user_{$uid}_{$uniqueId}_unpaid_order_list";
	}

	public static function sNewOrderCacheId($uid, $skuId): string
	{

		$date = Carbon::today()->format('Ymd');

		$key = "{$uid}_{$date}_{$skuId}_order";
		$topId = Redis::get($key);
		if(!$topId){
			Redis::set($key,0);
		}
		Redis::incr($key);

		$uniqueId = Redis::get($key);
		return "{$uid}_{$date}_{$skuId}_{$uniqueId}_order";
	}

	public static function sNewSeckillOrderCacheId($uid, $sid): string
	{

		$date = Carbon::today()->format('Ymd');

		$key = "{$uid}_{$date}_{$sid}_seckill";
		$topId = Redis::get($key);
		if(!$topId){
			Redis::set($key,0);
		}
		Redis::incr($key);

		$uniqueId = Redis::get($key);
		return "{$uid}_{$date}_{$sid}_{$uniqueId}_seckill";
	}

	public static function sAddOrderToUnpaidCache($uid, $skuId,$amount)
	{

		$newCacheId = self::sNewOrderCacheId($uid, $skuId);

		$sku = ProductSku::find($skuId);
		$product = $sku->product;
		
		
		$data = [
			'cid' => $newCacheId,
			'sid' => $skuId,
			'is_seckill' => false,
			'user_id' => $uid,
			'seckill_product_id' => 0,
			'order_id' => 0,
			'price_cost' => $sku->price_cost,
			'price_vip' => $sku->price_vip,
			'product_id' => $product->id,
			'product_sku_id' => $sku->id,
			'product_title' => $product->title,
			'product_cover' => $product->cover,
			'sku_name' => $sku->name,
			'sku_pic' => $sku->pic,
			'sku_attr_value_index' => $sku->attr_value_index,
			'sku_attr_value' => $sku->attr_value,
			'is_paid' => false,
			'created_at' => Carbon::now()->toDateTimeString(),
			'address' => '',
			'unallowed_area' =>  $product->unallowed_area
		];
		
		Redis::zAdd(self::sUnpaidOrderCacheKey($uid), 2, $newCacheId);
		Redis::hMset($newCacheId, $data);

		$user = self::find($uid);
		$items = [
            [
                'sku_id' => $skuId,
                'amount' => $amount
             ]
        ];
		$order = app(MakeProductOrder::class, [
            'user' => $user,
            'address' => null,
            'items' => $items,
            'cacheId' => $newCacheId
        ])->make();

		
		$queue = app()->environment('local') ? 'default' : 'close_order';
		dispatch(new CloseOrderJob($uid,$newCacheId))->onQueue($queue);
	}

	public static function sAddSeckilOrderToUnpaidCache($uid, $sid)
	{

		$newCacheId = self::sNewSeckillOrderCacheId($uid, $sid);

		$seckillProductCacheId = SeckillProduct::seckillProductAliveCacheKey($sid);
		
				
		$data = [
			'cid' => $newCacheId,
			'sid' => $sid,
			'user_id' => $uid,
			'seckill_product_id' => Redis::hGet($seckillProductCacheId, 'id'),
			'order_id' => 0,
			'price_cost' => Redis::hGet($seckillProductCacheId, 'price_cost'),
			'price_vip' => Redis::hGet($seckillProductCacheId, 'price_vip'),
			'product_id' => Redis::hGet($seckillProductCacheId, 'product_id'),
			'product_sku_id' => Redis::hGet($seckillProductCacheId, 'product_sku_id'),
			'product_title' => Redis::hGet($seckillProductCacheId, 'product_title'),
			'product_cover' => Redis::hGet($seckillProductCacheId, 'product_cover'),
			'sku_name' => Redis::hGet($seckillProductCacheId, 'sku_name'),
			'sku_pic' => Redis::hGet($seckillProductCacheId, 'sku_pic'),
			'sku_attr_value_index' => Redis::hGet($seckillProductCacheId, 'sku_attr_value_index'),
			'sku_attr_value' => Redis::hGet($seckillProductCacheId, 'sku_attr_value'),
			'is_paid' => false,
			'created_at' => Carbon::now()->toDateTimeString(),
			'address' => '',
			'unallowed_area' =>  Redis::hGet($seckillProductCacheId, 'unallowed_area')
		];
			
		$isPaying = Redis::hGet(User::sInfoCacheKey($uid),'is_paying');
		$isNew = Redis::hGet(User::sInfoCacheKey($uid),'is_new');
        
        if($isNew && !$isPaying){
        	 Redis::hMset(User::sInfoCacheKey($uid),['is_paying'=>true]);
        }

		Redis::zAdd(self::sUnpaidOrderCacheKey($uid), 1, $newCacheId);
		Redis::hMset($newCacheId, $data);

        $queue = app()->environment('local') ? 'default' : 'make_seckill_order';
        dispatch(new MakeSeckillOrderJob($uid, $newCacheId))->onQueue($queue);

		
		$queue = app()->environment('local') ? 'default' : 'close_seckill_order';
		dispatch(new CloseSeckillOrderJob($uid, $newCacheId))->onQueue($queue);
	}
  
    public function sAddOrderAddressToUnpaidCache($uid, $cacheIds,$address)
    {
    	$jsonStr = json_encode([
    			'address' => $address->full_address,
				'contact_name' => $address->contact_name,
				'contact_phone' => $address->contact_phone]
		);

        $data = [
        	'province' =>$address->province,
        	'city' =>$address->city,
        	'district' =>$address->district,
        	'address' => $jsonStr
        ];

        foreach($cacheIds as $v){

        	Redis::hMset($v, $data);
        	$queue = app()->environment('local') ? 'default' : 'make_seckill_order';
        	//dispatch(new MakeSeckillOrderAddressJob($uid,$v,$address))->onQueue($queue);
       		dispatch(new MakeSeckillOrderAddressJob($uid,$v,$address))->onQueue($queue);
        }
		

		

    }


    public function markRecordCacheAsMade(GoldRecord $record)
    {
        if ($record->user->is_mock) return;

        $cacheId = $record->cacheKey();

        Redis::hMset($cacheId, [
            'gold_record_id' => $record->id,
            'is_record_making' => false,
            'is_record_made' => true,
        ]);
    }


	/*==================================================================================================================*/



	/*public function unpaidRecordsCacheKey(): string
	{
		return self::sUnpaidRecordsCacheKey($this->id);
	}*/

	public function closeOrderFromUnpaidCache($unpaidCacheId)
	{
		Log::debug("Close unpaid cache id: {$unpaidCacheId}");

		Redis::transaction(function () use ($unpaidCacheId) {
			$sid = Redis::hGet($unpaidCacheId, 'seckill_product_id');
			if($sid){
				Redis::lpush(SeckillProduct::seckillProductQueueCacheKey($sid), 'a');
			}
			
			Redis::hMset($unpaidCacheId,['closed_at'=>Carbon::now()]);
			$this->addOrderToFinishedCache($unpaidCacheId);

 			$isPaying = Redis::hGet($this->infoCacheKey(),'is_paying');
			$unpaidOrder = Redis::zRange($this->unpaidOrderCacheKey(), 0,-1);

			if(!$unpaidOrder && $isPaying){

				 Redis::hMset($this->infoCacheKey(),['is_paying'=>false]);
			}
			
			Log::debug("Unpaid record cache: {$unpaidCacheId} closed");
		});
	}

	public function markOrderPayCachePaying($cacheId)
	{
		Redis::hMset($cacheId, ['is_paying' => true, 'is_paid' => false]);
	}

	public function markRecordCacheAsPaid(GoldRecord $record)
	{
		if ($record->user->is_mock) return;

		Redis::transaction(function () use ($record) {
			$cacheId = $record->cacheKey();
			$this->addRecordToPendingCache($cacheId);
			$this->delRecordFromUnpaidCache($cacheId);
			Redis::hMset($cacheId, [
				'gold_record_id' => $record->id,
				'is_paying' => false,
				'is_paid' => true,
			]);
			Log::debug("Unpaid record cache: {$cacheId} paid");
		});
	}

	public function unpaidOrderCacheKey()
	{
		return $this->sUnpaidOrderCacheKey($this->id);
	} 

	public function delOrderFromUnpaidCache($cacheId)
	{
		Redis::zRem($this->sUnpaidOrderCacheKey($this->id), $cacheId);
	}

	public function isOrderInUnpaidCache($cacheId)
	{
		return Redis::zScore($this->sUnpaidOrderCacheKey($this->id), $cacheId);
	}

	public function myUnpaidRecordsAllPrice()
	{
		$records = $this->myRecordsCache('unpaid');
		if ($records->isEmpty()) return 0;
		$money = big_decimal($records->sum('record_all_price'));
		return $money->toScale(2, RoundingMode::HALF_UP);
	}

	public function myUnpaidRecordsNetPrice()
	{
		$records = $this->myRecordsCache('unpaid');
		if ($records->isEmpty()) return 0;
		$money = big_decimal($records->sum('pay_net_price'));
		return $money->toScale(2, RoundingMode::HALF_UP);
	}

	public function myUnpaidRecordsCashPrice()
	{
		$records = $this->myRecordsCache('unpaid');
		if ($records->isEmpty()) return 0;
		$money = big_decimal($records->sum('pay_cash_price'));
		return $money->toScale(2, RoundingMode::HALF_UP);
	}

    public function myUnpaidRecordsBeans()
    {
        $records = $this->myRecordsCache('unpaid');
        if ($records->isEmpty()) return 0;
        $beans = big_decimal($records->sum('pay_gold_beans'));
        return $beans->toScale(2, RoundingMode::HALF_UP);
    }
}
